package com.lyn.sp;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;

import com.lyn.sp.annotation.BooleanDefaultValue;
import com.lyn.sp.annotation.FloatDefaultValue;
import com.lyn.sp.annotation.IntDefaultValue;
import com.lyn.sp.annotation.LongDefaultValue;
import com.lyn.sp.annotation.StringDefaultValue;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Sp核心
 *
 * @author Lyn 2022/12/18
 * @version 1.0.0
 */
public class SpImp implements Sp {
    private final SharedPreferences sp;

    public static final String DEFAULT_SP_NAME = "smatek_sp";
    private final Map<String, String> defaultStringValueMap = new ConcurrentHashMap<>();
    private final Map<String, Integer> defaultIntValueMap = new ConcurrentHashMap<>();
    private final Map<String, Float> defaultFloatValueMap = new ConcurrentHashMap<>();
    private final Map<String, Long> defaultLongValueMap = new ConcurrentHashMap<>();
    private final Map<String, Boolean> defaultBooleanValueMap = new ConcurrentHashMap<>();

    public SpImp(Context context, Class<?> defaultValueClass) {
        if (context == null) {
            throw new NullPointerException("context 不能为空!");
        }
        sp = context.getSharedPreferences(DEFAULT_SP_NAME, Context.MODE_PRIVATE);
        try {
            analysisDefaultValues(defaultValueClass);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public SpImp(Context context, String sp_name, Class<?> defaultValueClass) {
        if (context == null) {
            throw new NullPointerException("context 不能为空!");
        }
        if (TextUtils.isEmpty(sp_name)) {
            throw new NullPointerException("sp_name 不能为空!");
        }
        sp = context.getSharedPreferences(sp_name, Context.MODE_PRIVATE);
        try {
            analysisDefaultValues(defaultValueClass);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public SpImp(SharedPreferences sp, String sp_name, Class<?> defaultValueClass) {
        if (sp == null) {
            throw new NullPointerException("sp 不能为空!");
        }
        this.sp = sp;
        if (TextUtils.isEmpty(sp_name)) {
            throw new NullPointerException("sp_name 不能为空!");
        }
        try {
            analysisDefaultValues(defaultValueClass);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }


    /**
     * 解析默认值
     *
     * @param defaultValueClass 默认值类
     */
    private void analysisDefaultValues(Class<?> defaultValueClass) throws Throwable {
        Field[] fields = defaultValueClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = String.valueOf(field.get(null));
            if (field.isAnnotationPresent(StringDefaultValue.class)) {
                StringDefaultValue stringDefaultValue = field.getAnnotation(StringDefaultValue.class);
                String value = null;
                if (stringDefaultValue != null) {
                    value = stringDefaultValue.value();
                }
                defaultStringValueMap.put(fieldName, value);
                continue;
            }
            if (field.isAnnotationPresent(IntDefaultValue.class)) {
                IntDefaultValue intDefaultValue = field.getAnnotation(IntDefaultValue.class);
                int value = 0;
                if (intDefaultValue != null) {
                    value = intDefaultValue.value();
                }
                defaultIntValueMap.put(fieldName, value);
                continue;
            }
            if (field.isAnnotationPresent(BooleanDefaultValue.class)) {
                BooleanDefaultValue booleanDefaultValue = field.getAnnotation(BooleanDefaultValue.class);
                boolean value = false;
                if (booleanDefaultValue != null) {
                    value = booleanDefaultValue.value();
                }
                defaultBooleanValueMap.put(fieldName, value);
                continue;
            }
            if (field.isAnnotationPresent(FloatDefaultValue.class)) {
                FloatDefaultValue floatDefaultValue = field.getAnnotation(FloatDefaultValue.class);
                float value = 0f;
                if (floatDefaultValue != null) {
                    value = floatDefaultValue.value();
                }
                defaultFloatValueMap.put(fieldName, value);
                continue;
            }
            if (field.isAnnotationPresent(LongDefaultValue.class)) {
                LongDefaultValue longDefaultValue = field.getAnnotation(LongDefaultValue.class);
                long value = 0L;
                if (longDefaultValue != null) {
                    value = longDefaultValue.value();
                }
                defaultLongValueMap.put(fieldName, value);
            }
        }
    }

    @Override
    public String getString(String key) {
        return getString(key, (String) defaultStringValueMap.get(key));
    }

    @Override
    public String getString(String key, String defaultValue) {
        return sp.getString(key, defaultValue);
    }

    @Override
    public String setString(String key, String value) {
        sp.edit().putString(key, value).apply();
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public int getInt(String key) {
        return getInt(key, defaultIntValueMap.get(key));
    }

    @Override
    public int getInt(String key, int defaultValue) {
        return sp.getInt(key, defaultValue);
    }

    @Override
    public int setInt(String key, int value) {
        sp.edit().putInt(key, value).apply();
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public long getLong(String key) {
        return getLong(key, defaultLongValueMap.get(key));
    }

    @Override
    public long getLong(String key, long defaultValue) {
        return sp.getLong(key, defaultValue);
    }

    @Override
    public long setLong(String key, long value) {
        sp.edit().putLong(key, value).apply();
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public float getFloat(String key) {
        return getFloat(key, defaultFloatValueMap.get(key));
    }

    @Override
    public float getFloat(String key, float defaultValue) {
        return sp.getFloat(key, defaultValue);
    }

    @Override
    public float setFloat(String key, float value) {
        sp.edit().putFloat(key, value).apply();
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public boolean getBoolean(String key) {
        return getBoolean(key, defaultBooleanValueMap.get(key));
    }

    @Override
    public boolean getBoolean(String key, boolean defaultValue) {
        return sp.getBoolean(key, defaultValue);
    }

    @Override
    public boolean setBoolean(String key, boolean value) {
        sp.edit().putBoolean(key, value).apply();
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public void clear() {
        sp.edit().clear().apply();
        try {
            Runtime.getRuntime().exec("sync");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
